#include <nice2d/piece/piecescene.h>
#include <nice2d/piece/factionmanager.h>
#include <nice2d/piece/piecevisitor.h>
#include <nice2d/components/done.h>
#include <nice2d/tilemap.h>
#include <nice2d/application.h>
#include <nice2d/util.h>

IMPLEMENT_OBJECT(PieceScene,Scene)

class PieceSceneData
{
public:
    PieceSceneData(PieceScene* pieceScene):
        scene(pieceScene)
    {
    }

    void updateRound()
    {
        round ++;
        makeAppPiecesNotDone();
    }

    void makeAppPiecesNotDone()
    {
        auto faction = factionManager->getCurrentFaction();
        auto visitor = std::make_shared<SpecifiedColorPieceVisitor>(faction->getColor());
        scene->acceptPieces(visitor);

        auto pieces = visitor->getPieces();
        auto itr = pieces.begin();
        while(itr != pieces.end())
        {
            std::shared_ptr<Piece> piece = *itr;
            GET_COMPONENT(piece,Done)->setDone(false);
            itr ++;
        }
    }

    void actionStoped()
    {
        auto faction = factionManager->getCurrentFaction();
        std::shared_ptr<SpecifiedColorPieceNotDoneVisitor> visitor = std::make_shared<SpecifiedColorPieceNotDoneVisitor>(faction->getColor());

        scene->acceptPieces(visitor);

        auto pieces = visitor->getPieces();
        if(pieces.empty())
        {
            factionManager->switchFaction();
            makeAppPiecesNotDone();
        }
        else
        {
            auto controller = faction->getFactionController();
            if(controller)
                controller->reqireNewAction();
        }
    }

    void tileClicked(int32_t x, int32_t y)
    {
        auto tile = tileMap->getTileByIndex(x,y);

    }

    PieceScene* scene = nullptr;
    std::shared_ptr<TileMap> tileMap;
    std::list<std::shared_ptr<Piece>> pieces;

    int round = 1;

    std::shared_ptr<FactionManager> factionManager;
};

PieceScene::PieceScene():
    data(new PieceSceneData(this))
{
    data->factionManager = ADD_COMPONENT(Application::getInstance(),FactionManager);
    data->factionManager->newRound.connect(std::bind(&PieceSceneData::updateRound,data.get()));
}

PieceScene::~PieceScene()
{
    //data->factionManager->newRound.disconnect()
}

void PieceScene::setTileMap(std::shared_ptr<TileMap> tileMap)
{
    if(tileMap)
    {
        data->tileMap = tileMap;
        //data->tileMap->tileClicked.connect(std::bind(&PieceSceneData::tileClicked,data.get(),std::placeholders::_1,std::placeholders::_2));
    }
}

std::shared_ptr<TileMap> PieceScene::getTileMap() const
{
    return data->tileMap;
}

void PieceScene::addPiece(std::shared_ptr<Piece> piece, int32_t x, int32_t y)
{
    if(!piece)
        return;

    assert(data->tileMap);

    auto tile = data->tileMap->getTileByIndex(x,y);
    if(tile)
    {
        piece->configurate();
        auto position = tile->getPosition();
        piece->setCenter(position);
        data->pieces.push_back(piece);
        addChild(piece);

        tile->setSprite(piece);
        piece->setConfiguratedTile(tile);
    }
}

void PieceScene::removePiece(std::shared_ptr<Piece> piece)
{
    if(!piece)
    {
        data->pieces.remove(piece);
        detachChild(piece);
    }
}

void PieceScene::movePiece(std::shared_ptr<Piece> piece, int32_t x, int32_t y)
{
    if(!piece || !piece->isConfigurated())
        return;

    auto oldTile = piece->getConfiguratedTile();
    if(oldTile.expired())
        return;

    auto tile = getTileMap()->getTileByIndex({x,y});
    if(tile)
    {
        oldTile.lock()->clearSprite();
        tile->setSprite(piece);
    }
}

void PieceScene::selectPiece(std::shared_ptr<Piece> piece)
{
    if(piece)
    {
        piece->select();

        auto visitor = std::make_shared<SpecifiedColorPieceVisitor>(piece->getSpriteColor());
        acceptPieces(visitor);

        auto pieces = visitor->getPieces();
        auto itr = pieces.begin();
        while(itr != pieces.end())
        {
            if(*itr != piece)
                (*itr)->unselect();
            itr ++;
        }
    }
}

void PieceScene::acceptPieces(std::shared_ptr<PieceVisitor> visitor)
{
    if(visitor)
    {
        auto itr = data->pieces.begin();
        while(itr != data->pieces.end())
        {
            visitor->visitPiece(*itr);
            itr ++;
        }
    }
}

void PieceScene::execute(std::shared_ptr<Action> action)
{
    if(action)
    {
        action->stoped.connect(std::bind(&PieceSceneData::actionStoped,data.get()));
        runAction(action);
    }
}

int PieceScene::getCurrentRound() const
{
    return data->round;
}

void PieceScene::onUpdateScene(float deltaTime)
{

}

